package cn.dvptech.remotecontrol.screenmirror.sender.packets;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 用于二进制数据操作的实用程序类。
 */
public class Util {

    private static final String HEXES = "0123456789ABCDEF";

    /**
     * 将一个无符号 32 位整数以大端序写入输出流。
     *
     * @param out   要写入的输出流。
     * @param value 要写入的无符号 32 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static void writeUnsignedInt32(OutputStream out, int value) throws IOException {
        out.write((byte) (value >>> 24));
        out.write((byte) (value >>> 16));
        out.write((byte) (value >>> 8));
        out.write((byte) value);
    }

    /**
     * 从输入流中以大端序读取一个无符号 32 位整数。
     *
     * @param in 要读取的输入流。
     * @return 读取的无符号 32 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static int readUnsignedInt32(InputStream in) throws IOException {
        return ((in.read() & 0xff) << 24) | ((in.read() & 0xff) << 16) | ((in.read() & 0xff) << 8) | (in.read() & 0xff);
    }

    /**
     * 从输入流中以大端序读取一个无符号 24 位整数。
     *
     * @param in 要读取的输入流。
     * @return 读取的无符号 24 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static int readUnsignedInt24(InputStream in) throws IOException {
        return ((in.read() & 0xff) << 16) | ((in.read() & 0xff) << 8) | (in.read() & 0xff);
    }

    /**
     * 从输入流中以大端序读取一个无符号 16 位整数。
     *
     * @param in 要读取的输入流。
     * @return 读取的无符号 16 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static int readUnsignedInt16(InputStream in) throws IOException {
        return ((in.read() & 0xff) << 8) | (in.read() & 0xff);
    }

    /**
     * 将一个无符号 24 位整数以大端序写入输出流。
     *
     * @param out   要写入的输出流。
     * @param value 要写入的无符号 24 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static void writeUnsignedInt24(OutputStream out, int value) throws IOException {
        out.write((byte) (value >>> 16));
        out.write((byte) (value >>> 8));
        out.write((byte) value);
    }

    /**
     * 将一个无符号 16 位整数以大端序写入输出流。
     *
     * @param out   要写入的输出流。
     * @param value 要写入的无符号 16 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static void writeUnsignedInt16(OutputStream out, int value) throws IOException {
        out.write((byte) (value >>> 8));
        out.write((byte) value);
    }

    /**
     * 将一个字节数组转换为一个无符号 32 位整数（大端序）。
     *
     * @param bytes 要转换的字节数组。
     * @return 字节数组表示的无符号 32 位整数。
     */
    public static int toUnsignedInt32(byte[] bytes) {
        return (((int) bytes[0] & 0xff) << 24) | (((int)bytes[1] & 0xff) << 16) | (((int)bytes[2] & 0xff) << 8) | ((int)bytes[3] & 0xff);
    }

    /**
     * 将一个字节数组转换为一个无符号 32 位整数（小端序）。
     *
     * @param bytes 要转换的字节数组。
     * @return 字节数组表示的无符号 32 位整数。
     */
    public static int toUnsignedInt32LittleEndian(byte[] bytes) {
        return ((bytes[3] & 0xff) << 24) | ((bytes[2] & 0xff) << 16) | ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff);
    }

    /**
     * 将一个无符号 32 位整数以小端序写入输出流。
     *
     * @param out   要写入的输出流。
     * @param value 要写入的无符号 32 位整数。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static void writeUnsignedInt32LittleEndian(OutputStream out, int value) throws IOException {
        out.write((byte) value);
        out.write((byte) (value >>> 8));
        out.write((byte) (value >>> 16));
        out.write((byte) (value >>> 24));
    }

    /**
     * 将一个字节数组转换为一个无符号 24 位整数（大端序）。
     *
     * @param bytes 要转换的字节数组。
     * @return 字节数组表示的无符号 24 位整数。
     */
    public static int toUnsignedInt24(byte[] bytes) {
        return ((bytes[1] & 0xff) << 16) | ((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff);
    }

    /**
     * 将一个字节数组转换为一个无符号 16 位整数（大端序）。
     *
     * @param bytes 要转换的字节数组。
     * @return 字节数组表示的无符号 16 位整数。
     */
    public static int toUnsignedInt16(byte[] bytes) {
        return ((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff);
    }

    /**
     * 将一个字节数组转换为一个十六进制字符串。
     *
     * @param raw 要转换的字节数组。
     * @return 字节数组的十六进制字符串表示形式。
     */
    public static String toHexString(byte[] raw) {
        if (raw == null) {
            return null;
        }
        final StringBuilder hex = new StringBuilder(2 * raw.length);
        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
        }
        return hex.toString();
    }

    /**
     * 将一个字节转换为一个十六进制字符串。
     *
     * @param b 要转换的字节。
     * @return 字节的十六进制字符串表示形式。
     */
    public static String toHexString(byte b) {
        return new StringBuilder().append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))).toString();
    }

    /**
     * 从指定的输入流中读取字节到指定的缓冲区，直到缓冲区被填满。
     *
     * @param in           要读取的输入流。
     * @param targetBuffer 要填充字节的缓冲区。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static void readBytesUntilFull(InputStream in, byte[] targetBuffer) throws IOException {
        int totalBytesRead = 0;
        int read;
        final int targetBytes = targetBuffer.length;
        do {
            read = in.read(targetBuffer, totalBytesRead, (targetBytes - totalBytesRead));
            if (read != -1) {
                totalBytesRead += read;
            } else {
                throw new IOException("Unexpected EOF reached before read buffer was filled");
            }
        } while (totalBytesRead < targetBytes);
    }

    /**
     * 将一个 double 值转换为一个字节数组（大端序）。
     *
     * @param d 要转换的 double 值。
     * @return double 值的字节数组表示形式。
     */
    public static byte[] toByteArray(double d) {
        long l = Double.doubleToRawLongBits(d);
        return new byte[]{
                    (byte) ((l >> 56) & 0xff),
                    (byte) ((l >> 48) & 0xff),
                    (byte) ((l >> 40) & 0xff),
                    (byte) ((l >> 32) & 0xff),
                    (byte) ((l >> 24) & 0xff),
                    (byte) ((l >> 16) & 0xff),
                    (byte) ((l >> 8) & 0xff),
                    (byte) (l & 0xff),};
    }

    /**
     * 将一个无符号 32 位整数转换为一个字节数组（大端序）。
     *
     * @param value 要转换的无符号 32 位整数。
     * @return 无符号 32 位整数的字节数组表示形式。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static byte[] unsignedInt32ToByteArray(int value) throws IOException {
        return new byte[]{
                    (byte) (value >>> 24),
                    (byte) (value >>> 16),
                    (byte) (value >>> 8),
                    (byte) value};
    }

    /**
     * 从输入流中读取一个 double 值。
     *
     * @param in 要读取的输入流。
     * @return 读取的 double 值。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static double readDouble(InputStream in) throws IOException {
        long bits = ((long) (in.read() & 0xff) << 56) | ((long) (in.read() & 0xff) << 48) | ((long) (in.read() & 0xff) << 40) | ((long) (in.read() & 0xff) << 32) | ((in.read() & 0xff) << 24) | ((in.read() & 0xff) << 16) | ((in.read() & 0xff) << 8) | (in.read() & 0xff);
        return Double.longBitsToDouble(bits);
    }

    /**
     * 将一个 double 值写入输出流。
     *
     * @param out 要写入的输出流。
     * @param d   要写入的 double 值。
     * @throws IOException 如果发生 I/O 错误。
     */
    public static void writeDouble(OutputStream out, double d) throws IOException {
        long l = Double.doubleToRawLongBits(d);
        out.write(new byte[]{
                    (byte) ((l >> 56) & 0xff),
                    (byte) ((l >> 48) & 0xff),
                    (byte) ((l >> 40) & 0xff),
                    (byte) ((l >> 32) & 0xff),
                    (byte) ((l >> 24) & 0xff),
                    (byte) ((l >> 16) & 0xff),
                    (byte) ((l >> 8) & 0xff),
                    (byte) (l & 0xff)});
    }
}
